#ifndef scene_H
#define scene_H

#include <string>
#include "rtcore/rtcore.h"
#include "common/sys/tasking.h"
#include "common/math/col3.h"
#include "globals.h"
#include "shader.h"
#include "material.h"
#include "light_emitting_material.h"
#include "color.h"
#include "triangle.h"
#include "intersection.h"
#include "configurable.h"
#include "light_path.h"
#include <limits>
#include <list>

namespace gemren
{


	struct intersection;
	class scene : public configurable
	{
	public:
		const std::string& material_name(material_ptr mat) const;
		typedef embree::Vec3f coord;
		typedef std::vector<light_source*> light_cont;
		typedef light_cont::const_iterator light_iterator;
		scene(const color_converter& conv);
		scene();
		embree::Col3f ray_color(float wavelength) const
		{
			return conv.wavelength_color(wavelength);
		}
		~scene();
		
		light_iterator lbegin()const{ return lights.begin();}
		light_iterator lend()const{ return lights.end();}
		triangle* tbegin()const{ return triangles;}
		triangle* tend()const{ return triangles+tri_cnt;}
		void build_accel();
		void testinit();
		const color_converter& get_converter() const { return conv; }
		bool first_intersection(intersection& i, const coord& orig, const coord& dir, float from = 0.0f, float to = std::numeric_limits<float>::infinity()) const;
		bool point_occluded(const coord& src, const coord& dir, const float near, const float far) const;
		void store_material(const std::string& name, material_ptr mat); //may change the name for uniqueness
		//void set_background(float_type distance, shader_ptr shader);
		float light_selection_probability(const light_emitting_material* lmat) const;
		void reset();
		void add_geometry(  const std::list<triangle>& tris, 
							const std::list<coord>& verts,
							const std::list<coord>& normals,
							const std::list<coord2d>& texcoords);
		const triangle& get_triangle(size_t ind) const
		{
			return triangles[ind];
		}
		const coord& get_vertex(size_t ind) const
		{
			return vertices[ind];
		}
		const size_t tri_count() const { return tri_cnt; }
		size_t get_light_triangle(random& r) const;
		//configurators
		virtual void announce_properties(const std::string& prefix, property_announcer announcer);
		virtual err_t set_string(std::string& name, const std::string& value); //needs to catch caustic-changing parameters
		
		void direct_lighting(random* ran, intersection* i)const;
		void build_light_paths();
		coord triangle_area_sample(random& r, size_t tri);
		unsigned int get_lighting_mode()const { return lighting_mode; }
		void finish_caustic_mis_coef(intersection* i) const{ return lightpaths.finish_caustic_mis_coef(i, this); }
	protected:
		configurable* get_conf_target(const std::string& name);
		virtual err_t set_my_string(std::string& name, const std::string& value);
		
		template<typename T>
		static void add_elms(T*& cont, size_t& cnt, const std::list<T>& elms)
		{
			T* nc = (T*) malloc(sizeof(T)*(cnt+elms.size()));
			if(cnt>0) copy(cont, cont+cnt, nc);
			copy(elms.begin(), elms.end(), nc+cnt);
			cnt += elms.size();
			delete[] cont;
			cont = nc;
		}
		
		unsigned int lighting_mode;
		light_paths lightpaths;
		color_converter conv;
		float* lightprobs;

		light_cont lights;
		material_cont materials;
		embree::Ref<embree::Intersector> accel;
		
		//shader_ptr background_shader;
		//float background_distance;
		
		triangle* triangles;
		coord* vertices;
		coord* normals;
		coord2d* texcoords;

		size_t tri_cnt, ver_cnt, nor_cnt, tex_cnt;
	private:
		scene(const scene&); //not to be used
		scene& operator =(const scene&);
	};



	
}
#endif